package ananly;

import oracle.jdbc.driver.OracleConnection;
import oracle.jdbc.driver.OracleOCIConnection;
import oracle.xml.parser.v2.DOMParser;
import oracle.xml.parser.v2.XMLDocument;
import oracle.xml.parser.v2.XMLElement;
import org.w3c.dom.Element;
import org.w3c.dom.NodeList;
import org.w3c.dom.Text;
import org.xml.sax.SAXException;

import java.io.*;
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.SQLException;

public class ConnectionProvider extends Object {
  public static final boolean DEBUG = true; 

  protected OracleConnection connection; 

  protected XMLDocument connectionDefinition;

  public static final String CONNECTION = "Connection"; 
  public static final String DRIVER = "Driver"; 
  public static final String HOSTNAME = "Hostname"; 
  public static final String PORT = "Port"; 
  public static final String SID = "SID"; 
  public static final String SERVICENAME = "ServiceName"; 
  public static final String SERVERMODE = "Server"; 
  public static final String SCHEMA = "Schema"; 
  public static final String PASSWORD = "Password"; 
  public static final String POOL = "Pool"; 
  public static final String THIN_DRIVER = "thin"; 
  // public static final String OCI_DRIVER = "oci8"; 

  public static final String DEFAULT_CONNECTION_DEFINITION = "E:\\yhx\\work\\bigData\\src\\main\\resources\\connection.xml";
  public static final String DEFAULT_DRIVER = THIN_DRIVER; 
  public static final String DEFAULT_HOSTNAME = "localhost"; 
  public static final String DEFAULT_PORT = "1521"; 
  public static final String DEFAULT_SERVERMODE = "DEDICATED"; 

  public static final String TARGET_DIRECTORY = "targetDirectory"; 

  protected PrintStream log;

  public ConnectionProvider() { 

  } 

  public void initializeConnection() throws SAXException, IOException,
          SQLException {
    this.initializeConnection(System.out); 
  } 

  public void initializeConnection(PrintStream log) throws SAXException, 
      IOException, SQLException { 
    DriverManager.registerDriver(new oracle.jdbc.driver.OracleDriver());
    this.log = log; 
    loadConnectionSettings(); 
    this.connection = openConnection(); 
  } 

  public ConnectionProvider getConnectionProvider() { 
    return this; 
  } 

  public void initalizeConnection(String connectionLocation, PrintStream log) 
      throws SAXException, IOException, SQLException { 
    DriverManager.registerDriver(new oracle.jdbc.driver.OracleDriver()); 
    this.log = log; 
    loadConnectionSettings(connectionLocation); 
    this.connection = openConnection(); 
  } 

  public void setLogger(PrintStream log) { 
    this.log = log; 
  } 

  private void setConnectionSettings(XMLDocument doc) { 
    this.connectionDefinition = doc; 
  } 

  private void dumpConnectionSettings() throws IOException { 
    StringWriter sw = new StringWriter();
    PrintWriter pw = new PrintWriter(sw);
    this.connectionDefinition.print(pw); 
    pw.close(); 
    sw.close(); 
  } 

  public OracleConnection getConnection() throws SQLException {
    return this.connection; 
  } 

  public void closeConnection(Connection conn) throws Exception {
    if (isPooled()) { 
      conn.close(); 
    } 
  } 

  public Connection getConnection(String schema, String passwd) 
      throws Exception { 
    if (isPooled()) { 
      return (OracleOCIConnection) this.getConnection(schema, passwd);
    } else { 
      return this.connection; 
    } 
  } 

  public String getSetting(String nodeName) { 
    return getSetting(nodeName, null); 
  } 

  public String getSetting(String nodeName, String defaultValue) { 
    XMLElement root = (XMLElement) this.connectionDefinition
        .getDocumentElement(); 
    NodeList children = root.getChildrenByTagName(nodeName);
    if (children.getLength() != 0) { 
      Element element = (Element) children.item(0);
      Text text = (Text) element.getFirstChild();
      if (text != null) { 
        return text.getData(); 
      } 
    } 
    return defaultValue; 
  } 

  protected String getDriver() { 
    return getSetting(DRIVER, DEFAULT_DRIVER); 
  } 

  protected String getHostname() { 
    return getSetting(HOSTNAME, DEFAULT_HOSTNAME); 
  } 

  protected String getPort() { 
    return getSetting(PORT, DEFAULT_PORT); 
  } 

  protected String getServerMode() { 
    return getSetting(SERVERMODE, DEFAULT_SERVERMODE); 
  } 

  protected String getServiceName() { 
    return getSetting(SERVICENAME); 
  } 

  protected String getSID() { 
    return getSetting(SID); 
  } 

  protected boolean isPooled() { 
    String usePool = getSetting(POOL, Boolean.FALSE.toString()); 
    return !usePool.equalsIgnoreCase(Boolean.FALSE.toString()); 
  } 

  protected String getSchema() { 
    return getSetting(SCHEMA); 
  } 

  protected String getPassword() { 
    return getSetting(PASSWORD); 
  } 

  public void loadConnectionSettings() throws IOException, SAXException { 
    String filename = System.getProperty( 
        "com.oracle.st.xmldb.pm.ConnectionParameters", 
        this.DEFAULT_CONNECTION_DEFINITION); 
    loadConnectionSettings(filename); 
  } 

  public void loadConnectionSettings(String filename) throws IOException, 
      SAXException { 
    if (DEBUG) { 
      System.out 
          .println("Using connection.xml Parameters from : " + filename);
    } 
    Reader reader = new FileReader(new File(filename));
    DOMParser parser = new DOMParser();
    parser.parse(reader); 
    XMLDocument doc = parser.getDocument(); 
    setConnectionSettings(doc); 
    if (DEBUG) { 
      dumpConnectionSettings(); 
    } 
  } 

  protected String getDatabaseURL() { 
    if (getDriver() != null) { 
      if (getDriver().equalsIgnoreCase(THIN_DRIVER)) { 
        return "jdbc:oracle:thin:@" + getHostname() + ":" + getPort() 
            + ":" + getSID(); 
      } else { 
        return "jdbc:oracle:oci8:@(description=(address=(host=" 
            + getHostname() + ")(protocol=tcp)(port=" + getPort() 
            + "))(connect_data=(service_name=" + getServiceName() 
            + ")(server=" + getServerMode() + ")))"; 
      } 
    } else { 
      return null; 
    } 
  } 

  private OracleConnection openConnection() throws SQLException { 
    String user = getSchema(); 
    String password = getPassword(); 
    String connectionString = user + "/" + password + "@" 
        + getDatabaseURL(); 
    OracleConnection conn = null; 
    if (DEBUG) { 
      this.log 
          .println("ConnectionProvider.establishConnection(): Connecting as " 
              + connectionString); 
    } 
    try { 
      conn = (OracleConnection) DriverManager.getConnection( 
          getDatabaseURL(), user, password); 
      if (DEBUG) { 
        this.log 
            .println("ConnectionProvider.establishConnection(): Database Connection Established"); 
      } 
    } catch (SQLException sqle) { 
      int err = sqle.getErrorCode(); 
      this.log 
          .println("ConnectionProvider.establishConnection(): Failed to connect using " 
              + connectionString); 
      sqle.printStackTrace(this.log); 
      throw sqle; 
    } 
    return conn; 
  } 

  public OracleConnection getNewConnection() throws SQLException { 
    return openConnection(); 
  } 

  public XMLDocument getConnectionSettings() { 
    return this.connectionDefinition; 
  } 
}